package com.miracle.pagestate

import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment


class PageStateView @JvmOverloads constructor(
    mContext: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(mContext, attrs, defStyleAttr) {

    private var loadingLayoutId: Int = R.layout.lib_custom_loading_state_layout
    private var emptyLayoutId: Int = R.layout.lib_custom_empty_state_layout
    private var netErrorLayoutId: Int = R.layout.lib_custom_net_error_state_layout
    private var serverErrorLayoutId: Int = R.layout.lib_custom_server_error_state_layout
    private var textColor: Int = Color.BLACK
    private var textSize: Float = 16.0f
    private var refreshListener: OnRefreshListener? = null

    // 原始内容 View
    private lateinit var contentView: View

    // 当前显示的 View
    private var currentView: View? = null

    // 状态布局 View 缓存集合
    private val viewArray = SparseArray<View>()

    init {
        if (attrs != null) {
            initAttr(attrs)
        }
    }

    companion object {
        fun bindView(activity: Activity): PageStateView {
            val targetView = activity.findViewById<ViewGroup>(android.R.id.content).getChildAt(0)
            return bindView(targetView)
        }

        fun bindView(activity: Activity, viewId: Int): PageStateView {
            val rootView = activity.findViewById<ViewGroup>(android.R.id.content).getChildAt(0)
            val targetView = rootView.findViewById<ViewGroup>(viewId)
            return bindView(targetView)
        }

        fun bindView(fragment: Fragment, viewId: Int): PageStateView {
            val rootView = fragment.view
            val targetView = rootView?.findViewById<ViewGroup>(viewId)
            return bindView(targetView)
        }

        private fun bindView(targetView: View?): PageStateView {
            if (targetView == null) {
                throw RuntimeException("ContentView can not be null!")
            }

            val parent =
                targetView.parent ?: throw RuntimeException("ContentView must have a parent view!")
            parent as ViewGroup

            val lp = targetView.layoutParams
            val index: Int = parent.indexOfChild(targetView)
            parent.removeView(targetView)

            val pageStateView = PageStateView(targetView.context)
            pageStateView.addView(targetView)
            pageStateView.contentView = targetView
            pageStateView.currentView = targetView
            parent.addView(pageStateView, index, lp)

            return pageStateView
        }

    }


    private fun initAttr(attributes: AttributeSet) {
        val obtainStyledAttributes =
            context.obtainStyledAttributes(attributes, R.styleable.PageStateView)

        loadingLayoutId = obtainStyledAttributes.getResourceId(
            R.styleable.PageStateView_loading_view,
            loadingLayoutId
        )
        emptyLayoutId = obtainStyledAttributes.getResourceId(
            R.styleable.PageStateView_empty_view,
            emptyLayoutId
        )
        netErrorLayoutId = obtainStyledAttributes.getResourceId(
            R.styleable.PageStateView_net_error_view,
            netErrorLayoutId
        )
        serverErrorLayoutId = obtainStyledAttributes.getResourceId(
            R.styleable.PageStateView_server_error_view,
            serverErrorLayoutId
        )

        textSize = obtainStyledAttributes.getDimension(R.styleable.PageStateView_text_size, 16.0f)
        textColor =
            obtainStyledAttributes.getColor(R.styleable.PageStateView_text_color, Color.BLACK)

        obtainStyledAttributes.recycle()
    }

    /**
     * 在 XML 中使用时，布局文件加载完后获得 StatusView 对应的子 ContentView
     */
    override fun onFinishInflate() {
        super.onFinishInflate()
        if (childCount == 1) {
            val view = getChildAt(0)
            contentView = view
            currentView = contentView
        }
    }

    /**
     * 展示加载界面
     */
    fun showLoadingView() {
        switchStatusView(loadingLayoutId)
    }

    /**
     * 展示空界面
     */
    fun showEmptyView() {
        switchStatusView(emptyLayoutId)
    }

    /**
     * 展示网络异常界面
     */
    fun showNetErrorView() {
        switchStatusView(netErrorLayoutId)
    }

    /**
     * 展示服务器错误界面
     */
    fun showServerErrorView() {
        switchStatusView(serverErrorLayoutId)
    }

    /**
     * 展示正常数据界面
     */
    fun showContentView() {
        switchStatusView(contentView)
    }

    fun setLoadingView(@LayoutRes layoutId: Int) {
        this.loadingLayoutId = layoutId
    }

    fun setEmptyView(@LayoutRes layoutId: Int) {
        this.emptyLayoutId = layoutId
    }

    fun setNetErrorView(@LayoutRes layoutId: Int) {
        this.netErrorLayoutId = layoutId
    }

    fun setServerErrorView(@LayoutRes layoutId: Int) {
        this.serverErrorLayoutId = layoutId
    }

    private fun switchStatusView(@LayoutRes layoutId: Int) {
        val view = generateStatusView(layoutId)
        if (currentView == view) {
            return
        }
        removeView(currentView)
        currentView = view
        addView(currentView)
    }

    private fun switchStatusView(view: View) {
        if (currentView == view) {
            return
        }
        removeView(currentView)
        currentView = view
        addView(currentView)
    }

    private fun generateStatusView(@LayoutRes layoutId: Int): View {
        var statusView = viewArray.get(layoutId)
        if (statusView == null) {
            statusView = inflate(layoutId)
            viewArray.put(layoutId, statusView)
        }
        if (layoutId == serverErrorLayoutId || layoutId == netErrorLayoutId) {
            statusView.setOnClickListener {
                refreshListener?.onRefresh()
            }
        }

        return statusView
    }

    private fun inflate(@LayoutRes layoutId: Int): View {
        return LayoutInflater.from(context).inflate(layoutId, null)
    }

    fun setOnRefreshListener(listener: OnRefreshListener) {
        this.refreshListener = listener
    }

}